import random

from django.db import IntegrityError
from django.http import JsonResponse, FileResponse
from django.utils.encoding import escape_uri_path
from django.views import View
from django.db.models import Q
import os
import json
from django.contrib.auth.hashers import check_password

from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger

from services.TaskManager import FilePredictTask, DatasetPredictTask, TasksConsumer
from .models import GlobalTriples
from .models import User, AllDOC
from django.conf import settings
import threading
import traceback
from django.core.files.base import ContentFile

"""
(property) registerUser: {
name: string;
email: string;
password: string;
role: string;


  ROLES = (('admin', "admin"), ('user', "user"))
username = models.CharField('username', max_length=12, primary_key=True)
password = models.CharField('password', max_length=30)
email = models.EmailField('email', verbose_name="email", blank=False, null=False)
role = models.CharField('role', max_length=32, default="user", choices=ROLES)
}
"""
is_all_file_processed = False


def register(request):
    print(request)
    user_info = json.loads(request.body)
    username = user_info["name"]
    email = user_info["email"]
    password = user_info["password"]
    role = user_info["role"]
    try:
        user = User(username=username, email=email, password=password, role=role)
        user.save()
        id = user.id
        response = {
            "success": True,
            "msg": "注册成功！",
            "user_info": {
                "id": id,
                "username": username,
                "email": email,
                "role": role
            }
        }
        return JsonResponse(response)
    except IntegrityError:
        return JsonResponse({"success": False, "msg": "请不要重复注册！！"})
    except Exception as e:
        return JsonResponse({"success": False, "msg": "注册失败！"})


"""
(property) loginUser: {
    email: string;
    password: string;
}"""


def login(request):
    print(request)
    response = {}
    user_info = json.loads(request.body)
    email = user_info["email"]
    password = user_info["password"]
    try:
        user = User.objects.get(email=email)
        if check_password(password, user.password):
            response = {
                "success": True,
                "msg": "登陆成功！",
                "user_info": {
                    "id": user.id,
                    "username": user.username,
                    "email": user.email,
                    "role": user.role
                }
            }
        else:
            response["success"] = False
            response["username"] = None
            response["role"] = None
            response["msg"] = "登陆失败，密码错误！"
        return JsonResponse(response)
    except Exception:
        return JsonResponse({"success": False, "msg": "登陆失败，邮箱密码错误,请注册！"})


#  1
class UpFile(View):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.current_filename = None

    def post(self, request):
        print(request)
        response = {}
        try:
            file = request.FILES.get('file', '')
            username = "user_name"
            file_content = ContentFile(file.read())
            # file_name, full_name = self._save_file(file, username)
            file_name = file.name
            # response["filename"] = file_name

            doc = AllDOC(username=username, filename=file_name)
            doc.file.save(name=file_name, content=file_content, save=True)
            full_file_name = "{}{}".format(settings.BASE_DIR, doc.file.url)
            doc.fullname = full_file_name
            doc.save()
            # response["file_url"] =
            response["success"] = True
            # response["Processed"] = False
            global is_all_file_processed
            is_all_file_processed = False
        except Exception as e:
            print(e)
            response["success"] = False
            return JsonResponse(response)
        print(" up file ok")
        # ProcessFile().processAll()  # 可在其他地方调用
        return JsonResponse(response)

    # @staticmethod
    # def _save_file(file, username=""):
    #     BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    #     # file_name = "user_{}__{}".format(username, file.name)
    #     file_name = file.name
    #     full_name = os.path.join(settings.MEDIA_ROOT, file_name)
    #     if not os.path.exists(os.path.join(settings.MEDIA_ROOT)):  # 文件夹不存在则创建
    #         os.makedirs(os.path.join(settings.MEDIA_ROOT))
    #     if os.path.exists(full_name):
    #         os.remove(full_name)
    #     with open(full_name, "wb+") as f:  # 将文件存储到项目中
    #         for chunk in file.chunks():
    #             f.write(chunk)
    #     return file_name, full_name


def files(request):
    current_page = int(request.GET.get('page', 1))
    t_response = {}
    all_books = AllDOC.objects.all().order_by("id")
    if len(all_books) <= 10:
        num = len(all_books)
    else:
        num = 10
    paginator = Paginator(all_books, num)
    """
    paginator.per_page  # 每页显示数量
    paginator.count  # 数据总数
    paginator.num_pages  # 总页数
    paginator.page_range  # 页码范围
    paginator.page  # 页码范围
    """

    def get_file_list(objs):
        ret = []
        for obj in objs:
            ret.append({
                "uptime": obj.upDate.strftime('%Y年%m月%d日 %H:%M'),
                "id": obj.id,
                "filename": obj.filename,
                "file_url": obj.file.url,
                "username": obj.username,
                "Processed": obj.Processed,
            })
        return ret

    try:
        page = paginator.page(current_page)
        t_response["success"] = True
        t_response["msg"] = "book_list"
        t_response["obj_list"] = get_file_list(page.object_list)
        t_response["has_next"] = page.has_next()  # 是否有下一页
        t_response["next_page"] = page.next_page_number()
        """
        book_list.has_previous()  # 是否有上一页
        book_list.has_next()  # 是否有下一页
        """
    except PageNotAnInteger:
        page = paginator.page(1)
        t_response["obj_list"] = get_file_list(page.object_list)
        t_response["has_next"] = False
        t_response["success"] = True
        t_response["msg"] = "book_list"
    except EmptyPage or ZeroDivisionError:
        page = paginator.page(paginator.num_pages)
        t_response["obj_list"] = get_file_list(page.object_list)
        t_response["has_next"] = False
        t_response["success"] = True
        t_response["msg"] = "加载完毕"
    except Exception:
        traceback.print_exc()
        t_response["success"] = False
        t_response["msg"] = "无文件或查询失败"

    return JsonResponse(t_response)


class NodeSet(object):
    def __init__(self):
        self.node_set = list()
        self.symbolSize = dict()

    def add(self, name):
        if name not in self.node_set:
            self.node_set.append(name)
            self.symbolSize[name] = 15
        else:
            self.symbolSize[name] = min(self.symbolSize[name] + self.symbolSize[name] / 4, 30)

    def get_node_list(self):
        node_list = []
        for name in self.node_set:
            node = {
                "id": self.node_set.index(name),
                "name": name,
                "symbolSize": self.symbolSize[name],
                "category": random.choice([0, 1, 2]),
                "value": 10
            }
            node_list.append(node)
        return node_list

    def get_node_id(self, name):
        return self.node_set.index(name)


class Searcher(object):
    def __init__(self):
        super(Searcher, self).__init__()

    def search(self, search_content, search_length):
        if search_content == "[-all-]":
            g_Triples = GlobalTriples.objects.all()
        else:
            g_Triples = GlobalTriples.objects.filter(
                Q(mobject__icontains=search_content) |
                Q(subject__icontains=search_content) |
                Q(predict__icontains=search_content)).order_by()
        alldatalength = len(g_Triples)
        ret = {}
        # predict
        # mobject
        # subject
        if len(g_Triples) == 0:
            # predict = "predict"
            # mobject = "object"
            # subject = "subject"
            # globalTriples = GlobalTriples(mobject=mobject, predict=predict, subject=subject)
            # globalTriples.save()

            ret["nodes"] = [
                {
                    "id": 0,
                    "name": "empty",
                    "symbolSize": 20,
                    "category": 0,
                    "value": 10
                }
            ]
            ret["links"] = []
            ret["categories"] = [{"name": "empty"}]
            ret_dic = {
                "success": False,
                "msg": "查询结果为空",
                "alldatalength": 0,
                "data": ret
            }
            return ret_dic
        elif len(g_Triples) >= search_length:
            paginator = Paginator(g_Triples, search_length)
            page = paginator.page(1)
            g_Triples = page.object_list

        links = []
        node_set = NodeSet()
        for Triple in g_Triples:
            node_set.add(Triple.mobject)
            node_set.add(Triple.subject)
            link = {
                "source": node_set.get_node_id(Triple.mobject),
                "target": node_set.get_node_id(Triple.subject),
                "name": Triple.predict
            }
            links.append(link)
            # temp_pair = {
            #     "predict": Triple.predict,
            #     "mobject": Triple.mobject,
            #     "subject": Triple.subject,
            #     "type": Triple.type,
            #     "id": Triple.id
            # }
        ret["nodes"] = node_set.get_node_list()
        ret["links"] = links
        ret["categories"] = [{"name": "All"}, {"name": "All2"}, {"name": "All3"}]

        ret_dic = {
            "success": True,
            "msg": "查询成功",
            "alldatalength": min(alldatalength, 600),
            "data": ret
        }
        return ret_dic


class Search(View):
    def __init__(self, **kwargs) -> None:
        super().__init__(**kwargs)
        self.searcher = Searcher()

    def post(self, request):
        print(request)
        content = json.loads(request.body)
        search_content = str(content['search_content']).strip()
        search_length = int(content["search_length"])
        print("=====>>>>" + search_content)
        ret_dic = self.searcher.search(search_content=search_content, search_length=search_length)

        return JsonResponse(ret_dic)


class ProcessFile(object):
    msg = "正在处理..."
    Precessing = False

    def __init__(self):
        self.file_list = []
        self.taskConsumer = TasksConsumer()

    # {"predict_triple": ..., "text":...}
    # {"predicate": "/business/person/company", "object": "NASD", "subject": "Robert R. Glauber"}
    @staticmethod
    def _callBack(return_data, repofile):
        # todo error callback
        print("------call-back-----")
        text = return_data["text"]
        print("----add--triples .......---")
        for line_triples in return_data["predict_triple"]:
            if len(line_triples) == 0:
                continue
            for predict_t in line_triples:
                predict = predict_t["predicate"]
                mobject = predict_t["object"]
                subject = predict_t["subject"]
                globalTriples = GlobalTriples(mobject=mobject, predict=predict, subject=subject)
                globalTriples.save()
        repofile.Processed = True
        repofile.save()

    def __call__(self, *args, **kwargs):
        self.file_list = AllDOC.objects.filter(Processed=False)
        for file in self.file_list:
            file_type = file.filename.split('.')[-1]
            if file_type not in ("pdf", "PDF", "txt", "TXT"):
                task = DatasetPredictTask(repo_file=file, priority=0, callBack=self._callBack)
            else:
                task = FilePredictTask(priority=0, callBack=self._callBack, repo_file=file)
            self.taskConsumer.addTask(task=task)
        self.taskConsumer.executeNowait()

    def processAll(self):
        ProcessFile.msg = "正在处理..."
        ProcessFile.Precessing = True
        self()
        ProcessFile.Precessing = False
        global is_all_file_processed
        is_all_file_processed = True
        ProcessFile.msg = "处理库文件成功！"
        # process = Process(target=self())
        # process.start()


def flush_process(request):
    print(request)
    global is_all_file_processed
    try:
        if not is_all_file_processed and not ProcessFile.Precessing:
            th = threading.Thread(target=ProcessFile().processAll)
            th.setDaemon(True)
            th.start()
        t_response = {
            "success": True,
            "msg": ProcessFile.msg,
            "processing": not is_all_file_processed
        }
    except Exception as e:
        traceback.print_exc()
        print(e)
        t_response = {
            "success": False,
            "msg": "在文件实体关系提取时间发生错误！"
        }
    return JsonResponse(t_response)


class DownloadFile(View):  # todo 添加下载
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.seracher = Searcher()
        self.ret_dic = {}

    def post(self, request):
        print(request)
        content = json.loads(request.body)
        file_contents = str(content['search_content']).strip()
        search_length = int(content["search_length"])
        appearance = int(content["appearance"])

        search_result = self.seracher.search(search_content=file_contents, search_length=search_length)
        path = os.path.join(settings.MEDIA_ROOT, "temp_file\\graph.txt")
        f = open(path, 'w')
        print(path)

        store_json = json.dumps(
            {
                "header":
                    {
                        "file_contents": file_contents,
                        "nodes": search_result["alldatalength"],
                        "file_type": "json"
                    },
                "appearance": appearance,
                "data": search_result["data"]
            }, indent=4)

        f.write(store_json)
        f.flush()
        f.close()
        file = open(path, 'rb')
        file_name = "{}_graph.json".format(file_contents)
        response = FileResponse(file)
        response['Content-Type'] = 'application/octet-stream'
        response['Content-Disposition'] = "attachment; filename*=utf-8''{}".format(escape_uri_path(file_name))
        return response